"""
策略执行器 - 统一管理不同执行模式
支持：监控、实盘交易、模拟交易、回测
"""
import logging
import time
import threading
from abc import ABC, abstractmethod
from typing import Dict, List, Optional, Any
from enum import Enum
from datetime import datetime
from xtquant import xtdata
from utils.signal_formatter import TradeFormatter

logger = logging.getLogger('StrategyExecutor')

# 导入专业图表生成模块
# professional_charts 统一图表生成模块
# generate_professional_charts() 函数会在需要时动态导入

class ExecutionMode(Enum):
    """执行模式枚举"""
    MONITOR = "monitor"      # 监控模式
    LIVE_TRADE = "live"      # 实盘交易
    SIMULATE = "simulate"    # 模拟交易
    MINUTE_BACKTEST = "minute_backtest"  # 分钟级回测

class StrategyExecutor(ABC):
    """策略执行器基类"""
    
    def __init__(self, strategy_class, mode: ExecutionMode, **kwargs):
        self.strategy_class = strategy_class
        self.mode = mode
        self.config = kwargs
        self.is_running = False
        self.thread = None
        
    @abstractmethod
    def execute(self):
        """执行策略"""
        pass
    
    def start(self):
        """启动执行器"""
        if self.is_running:
            logger.warning("执行器已在运行中")
            return
        
        self.is_running = True
        self.thread = threading.Thread(target=self.execute, daemon=True)
        self.thread.start()
        logger.info(f"策略执行器已启动 - 模式: {self.mode.value}")
    
    def stop(self):
        """停止执行器"""
        self.is_running = False
        if self.thread:
            self.thread.join(timeout=5)
        logger.info("策略执行器已停止")

class MonitorExecutor(StrategyExecutor):
    """监控模式执行器 - 只监控不交易"""
    
    def __init__(self, strategy_class, **kwargs):
        super().__init__(strategy_class, ExecutionMode.MONITOR, **kwargs)
        self.strategy = None
        
    def execute(self):
        """监控执行逻辑"""
        try:
            # 创建策略实例（使用类方法工厂）
            self.strategy = self.strategy_class.for_live()
            
            # 获取目标股票和板块
            target_stocks = self.config.get('target_stocks', [])
            target_sectors = self.config.get('target_sectors', [])
            
            # ===== 监控模式：如果用户什么都没输入，提示警告 =====
            if not target_stocks and not target_sectors:
                logger.warning("⚠️ 未指定监控范围，监控模式将无股票可监控")
                logger.info("💡 提示：监控模式不涉及持仓，建议输入股票代码或板块")
            
            # 初始化策略数据
            if hasattr(self.strategy, 'initialize_data'):
                self.strategy.initialize_data(
                    mode="monitor", 
                    target_stocks=target_stocks, 
                    target_sectors=target_sectors
                )
            
            logger.info("开始监控模式...")
            logger.info("监控模式：只输出信号，不执行交易")
            if target_stocks:
                logger.info(f"📊 监控股票: {len(target_stocks)} 只")
            if target_sectors:
                logger.info(f"📊 监控板块: {', '.join(target_sectors)}")
            
            while self.is_running:
                try:
                    # 检查交易时间
                    if not self.strategy.check_market_status():
                        time.sleep(60)
                        continue
                    
                    # 监控所有股票
                    for stock in self.strategy.stock_pool:
                        try:
                            # 检查买入信号
                            if self.strategy.check_conditions(stock):
                                # 构建详细的买入原因（包含策略类型、量比、涨幅等）
                                try:
                                    stock_today_data = self.strategy.today_data.get(stock, {})
                                    volume_ratio = stock_today_data.get('volRatio', 0)
                                    price_change_pct = stock_today_data.get('changePct', 0) * 100
                                    strategy_type = self.strategy.last_strategy_type or "未知策略"
                                    
                                    # 构建详细买入原因
                                    buy_reason_parts = [f"({strategy_type}) 买入条件："]
                                    buy_reason_parts.append(f"突破5日线")
                                    buy_reason_parts.append(f"量比{volume_ratio:.2f}")
                                    if price_change_pct > 0:
                                        buy_reason_parts.append(f"涨幅+{price_change_pct:.2f}%")
                                    else:
                                        buy_reason_parts.append(f"涨幅{price_change_pct:.2f}%")
                                    buy_reason_parts.append("多头趋势")
                                    buy_reason_parts.append("量价配合")
                                    buy_reason = " + ".join(buy_reason_parts)
                                except Exception as e:
                                    buy_reason = "满足买入条件"
                                
                                logger.info(f"🔍 监控信号 - {stock}: {buy_reason}")
                            
                            # 检查卖出信号
                            sell_result = self.strategy.check_sell_conditions(stock)
                            if sell_result.get('should_sell', False):
                                sell_reason = sell_result.get('reason', '未知原因')
                                logger.info(f"🔍 监控信号 - {stock}: {sell_reason}")
                        
                        except Exception as e:
                            logger.error(f"监控{stock}时出错: {str(e)}")
                    
                    # 等待下次检查
                    time.sleep(30)  # 30秒检查一次
                    
                except Exception as e:
                    logger.error(f"监控执行异常: {str(e)}")
                    time.sleep(60)
                    
        except Exception as e:
            logger.error(f"监控模式启动失败: {str(e)}")

class LiveTradeExecutor(StrategyExecutor):
    """实盘交易执行器"""
    
    def __init__(self, strategy_class, trader_interface=None, **kwargs):
        super().__init__(strategy_class, ExecutionMode.LIVE_TRADE, **kwargs)
        self.trader = trader_interface  # 交易接口
        self.strategy = None
        
        # ===== 统一持仓管理器（管理所有持仓信息）=====
        from position_management.position_manager import PositionManager
        self.position_manager = PositionManager()
        
        # 初始化止损服务
        from utils.stop_loss_service import create_stop_loss_service
        self.stop_loss_service = create_stop_loss_service()
        
    def execute(self):
        """实盘交易执行逻辑"""
        try:
            # 创建策略实例（使用类方法工厂）
            self.strategy = self.strategy_class.for_live()
            
            # 获取目标股票和板块
            target_stocks = self.config.get('target_stocks', [])
            target_sectors = self.config.get('target_sectors', [])
            
            # ===== 第一步：同步已持仓的股票 =====
            holding_stocks = []
            if self.trader:
                try:
                    positions = self.trader.get_positions()
                    holding_stocks = list(positions.keys()) if positions else []
                    if holding_stocks:
                        logger.info(f"📦 同步到 {len(holding_stocks)} 只持仓股票: {', '.join(holding_stocks)}")
                        for stock, pos in positions.items():
                            logger.info(f"   {stock}: {pos.get('shares', 0)}股 @ {pos.get('cost_price', 0):.2f}元")
                except Exception as e:
                    logger.warning(f"获取持仓信息失败: {str(e)}")
            
            # ===== 第二步：合并监控范围 = 用户输入 + 持仓股票 =====
            # 将持仓股票自动加入监控范围
            if target_stocks:
                target_stocks = list(set(target_stocks) | set(holding_stocks))
            else:
                target_stocks = holding_stocks
            
            if holding_stocks:
                logger.info(f"✓ 监控范围已包含 {len(holding_stocks)} 只持仓股票")
            
            # 初始化策略数据
            if hasattr(self.strategy, 'initialize_data'):
                self.strategy.initialize_data(
                    mode="live", 
                    target_stocks=target_stocks, 
                    target_sectors=target_sectors
                )
            
            logger.info("开始实盘交易模式...")
            logger.warning("⚠️ 实盘交易模式 - 将执行真实交易！")
            if target_stocks:
                logger.info(f"📊 最终监控范围: {len(target_stocks)} 只股票")
            if target_sectors:
                logger.info(f"📊 监控板块: {', '.join(target_sectors)}")
            
            while self.is_running:
                try:
                    if not self.strategy.check_market_status():
                        time.sleep(60)
                        continue
                    
                    # ===== 优先级1：止损检查（使用止损服务）=====
                    self._check_stop_loss()
                    
                    # ===== 优先级2：策略卖出信号 =====
                    self._check_sell_signals()
                    
                    # ===== 优先级3：买入信号 =====
                    self._check_buy_signals()
                    
                    time.sleep(30)
                    
                except Exception as e:
                    logger.error(f"实盘交易执行异常: {str(e)}")
                    time.sleep(60)
                    
        except Exception as e:
            logger.error(f"实盘交易模式启动失败: {str(e)}")
    
    def _check_stop_loss(self):
        """检查止损（使用止损服务）"""
        if not self.stop_loss_service.is_enabled():
            return
        
        try:
            # 获取当前持仓
            positions = self.trader.get_positions() if self.trader else {}
            if not positions:
                return
            
            # 同步实盘持仓到 position_manager
            from position_management.position_manager import PositionInfo
            current_date = datetime.now().strftime('%Y%m%d')
            current_prices = {}
            
            for stock, position in positions.items():
                # 为每个持仓创建/更新 PositionInfo 对象
                if not self.position_manager.get_position(stock):
                    position_info = PositionInfo(
                        stock=stock,
                        buy_time=datetime.now(),  # 实盘无法追溯买入时间，使用当前时间
                        buy_price=position.get('cost_price', 0),
                        shares=position.get('shares', 0)
                    )
                    position_info.initialize_stop_loss()
                    self.position_manager.add_position(stock, position_info)
                
                # 获取当前价格
                current_prices[stock] = self.strategy.today_data.get(stock, {}).get('last', 0)
            
            # 直接从 position_manager 获取持仓进行止损检查
            all_positions = self.position_manager.get_all_positions()
            stop_loss_list = self.stop_loss_service.check_all_positions(
                positions=all_positions,
                current_prices=current_prices,
                current_date=current_date
            )
            
            # 执行止损
            for stock, reason in stop_loss_list:
                position = positions.get(stock)
                if position and self.trader:
                    logger.warning(f"🛑 触发止损: {stock} - {reason}")
                    # 全部清仓
                    self.trader.sell_stock(stock, position['shares'], reason)
                    # 从 position_manager 中移除
                    self.position_manager.remove_position(stock)
                    
                    # 更新监控范围
                    try:
                        updated_positions = self.trader.get_positions()
                        if hasattr(self.strategy, 'update_monitor_list'):
                            self.strategy.update_monitor_list(updated_positions)
                    except Exception as update_err:
                        logger.warning(f"更新监控范围失败: {str(update_err)}")
        
        except Exception as e:
            logger.error(f"止损检查异常: {str(e)}", exc_info=True)
    
    def _check_sell_signals(self):
        """检查卖出信号（支持分批减仓）"""
        # 获取当前持仓
        positions = self.trader.get_positions() if self.trader else {}
        
        for stock, position in positions.items():
            try:
                sell_result = self.strategy.check_sell_conditions(stock)
                if sell_result.get('should_sell', False):
                    # 支持分批减仓
                    sell_ratio = sell_result.get('sell_ratio', 1.0)  # 默认全部清仓
                    total_shares = position['shares']
                    sell_shares = int(total_shares * sell_ratio)
                    # 确保卖出股数是100的整数倍
                    sell_shares = (sell_shares // 100) * 100
                    
                    if sell_shares <= 0:
                        logger.warning(f"{stock} 计算卖出数量为0，跳过")
                        continue
                    
                    # 确保不超过持仓
                    sell_shares = min(sell_shares, total_shares)
                    
                    action_desc = "全部清仓" if sell_shares >= total_shares else f"减仓{sell_ratio*100:.0f}%"
                    
                    # 使用统一的交易输出格式化工具
                    trade_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                    
                    # 获取当前价格和股票名称
                    current_price = self.strategy.today_data.get(stock, {}).get('last', 0)
                    stock_name = stock
                    try:
                        detail = xtdata.get_instrument_detail(stock)
                        if isinstance(detail, dict):
                            stock_name_display = detail.get('InstrumentName', '')
                            if stock_name_display:
                                stock_name = f"{stock} ({stock_name_display})"
                    except:
                        pass
                    
                    # 计算盈亏信息
                    buy_price = position.get('buy_price', 0)
                    sell_amount = current_price * sell_shares if current_price > 0 else 0
                    profit = (current_price - buy_price) * sell_shares if buy_price > 0 else 0
                    profit_rate = (profit / (buy_price * sell_shares) * 100) if buy_price > 0 and sell_shares > 0 else 0
                    
                    # 计算持有天数
                    hold_days = 0
                    if 'buy_date' in position:
                        try:
                            buy_date = datetime.strptime(position['buy_date'], '%Y%m%d')
                            sell_time = datetime.now()
                            hold_days = (sell_time - buy_date).days
                        except:
                            hold_days = 0
                    
                    commission = sell_amount * 0.0001  # 默认手续费率
                    actual_sell_ratio = (sell_shares / total_shares * 100) if total_shares > 0 else 0
                    
                    # 输出卖出信号（使用统一格式）
                    output_lines = TradeFormatter.format_sell_output(
                        stock_name=stock_name,
                        trade_time=trade_time,
                        price=current_price,
                        actual_price=current_price,  # 实盘无滑点
                        slippage_rate=0.0,
                        shares=sell_shares,
                        sell_amount=sell_amount,
                        commission=commission,
                        remaining_capital=0,  # 实盘无法获取剩余资金
                        reason=f"{sell_result['reason']} ({action_desc})",
                        is_full_sell=(sell_shares >= total_shares),
                        planned_sell_ratio=sell_ratio * 100,
                        actual_sell_ratio=actual_sell_ratio,
                        remaining_shares=total_shares - sell_shares,
                        buy_price=buy_price,
                        profit=profit,
                        profit_rate=profit_rate,
                        hold_days=hold_days,
                        trigger_count=None
                    )
                    
                    # 输出到控制台
                    print()  # 换行
                    for line in output_lines:
                        logger.info(line)
                    
                    # 执行卖出
                    if self.trader:
                        self.trader.sell_stock(stock, sell_shares, sell_result['reason'])
                        
                        # ===== 卖出后同步持仓并更新监控范围 =====
                        try:
                            updated_positions = self.trader.get_positions()
                            if hasattr(self.strategy, 'update_monitor_list'):
                                self.strategy.update_monitor_list(updated_positions)
                        except Exception as update_err:
                            logger.warning(f"更新监控范围失败: {str(update_err)}")
            except Exception as e:
                logger.error(f"检查{stock}卖出信号失败: {str(e)}")
    
    def _check_buy_signals(self):
        """检查买入信号"""
        for stock in self.strategy.stock_pool:
            try:
                if self.strategy.check_conditions(stock):
                    # 构建详细的买入原因（包含策略类型、量比、涨幅等）
                    try:
                        stock_today_data = self.strategy.today_data.get(stock, {})
                        volume_ratio = stock_today_data.get('volRatio', 0)
                        price_change_pct = stock_today_data.get('changePct', 0) * 100
                        strategy_type = self.strategy.last_strategy_type or "未知策略"
                        
                        # 构建详细买入原因
                        buy_reason_parts = [f"({strategy_type}) 买入条件："]
                        buy_reason_parts.append(f"突破5日线")
                        buy_reason_parts.append(f"量比{volume_ratio:.2f}")
                        if price_change_pct > 0:
                            buy_reason_parts.append(f"涨幅+{price_change_pct:.2f}%")
                        else:
                            buy_reason_parts.append(f"涨幅{price_change_pct:.2f}%")
                        buy_reason_parts.append("多头趋势")
                        buy_reason_parts.append("量价配合")
                        buy_reason = " + ".join(buy_reason_parts)
                    except Exception as e:
                        buy_reason = "策略买入信号"
                    
                    # 使用统一的交易输出格式化工具
                    trade_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                    
                    # 获取当前价格和股票名称
                    current_price = stock_today_data.get('last', 0)
                    stock_name = stock
                    try:
                        detail = xtdata.get_instrument_detail(stock)
                        if isinstance(detail, dict):
                            stock_name_display = detail.get('InstrumentName', '')
                            if stock_name_display:
                                stock_name = f"{stock} ({stock_name_display})"
                    except:
                        pass
                    
                    # 计算买入数量（临时，实际由trader执行）
                    shares = self._calculate_buy_shares(stock)
                    amount = current_price * shares if current_price > 0 else 0
                    commission = amount * 0.0001  # 默认手续费率
                    total_cost = amount + commission
                    
                    # 输出买入信号（使用统一格式）
                    output_lines = TradeFormatter.format_buy_output(
                        stock_name=stock_name,
                        trade_time=trade_time,
                        price=current_price,
                        actual_price=current_price,  # 实盘无滑点
                        slippage_rate=0.0,
                        shares=shares,
                        amount=amount,
                        commission=commission,
                        total_cost=total_cost,
                        remaining_capital=0,  # 实盘无法获取剩余资金
                        reason=buy_reason,
                        planned_ratio=None,
                        actual_ratio=None
                    )
                    
                    # 输出到控制台
                    print()  # 换行
                    for line in output_lines:
                        logger.info(line)
                    
                    # 执行买入
                    if self.trader:
                        # 计算买入数量
                        shares = self._calculate_buy_shares(stock)
                        if shares > 0:
                            self.trader.buy_stock(stock, shares, buy_reason)
                            
                            # ===== 买入后同步持仓并更新监控范围 =====
                            try:
                                updated_positions = self.trader.get_positions()
                                if hasattr(self.strategy, 'update_monitor_list'):
                                    self.strategy.update_monitor_list(updated_positions)
                            except Exception as update_err:
                                logger.warning(f"更新监控范围失败: {str(update_err)}")
            except Exception as e:
                logger.error(f"检查{stock}买入信号失败: {str(e)}")
    
    def _calculate_buy_shares(self, stock):
        """计算买入数量"""
        # 这里可以根据资金管理规则计算买入数量
        return 100  # 示例：买入100股

class SimulateExecutor(StrategyExecutor):
    """模拟交易执行器"""
    
    def __init__(self, strategy_class, initial_capital=100000, **kwargs):
        super().__init__(strategy_class, ExecutionMode.SIMULATE, **kwargs)
        self.strategy = None
        self.capital = initial_capital
        self.trades = []
        
        # ===== 统一持仓管理器（管理所有持仓信息）=====
        from position_management.position_manager import PositionManager
        self.position_manager = PositionManager()
        
        # 初始化止损服务
        from utils.stop_loss_service import create_stop_loss_service
        self.stop_loss_service = create_stop_loss_service()
        
    def execute(self):
        """模拟交易执行逻辑"""
        try:
            # 创建策略实例（使用类方法工厂）
            self.strategy = self.strategy_class.for_live()
            
            # 获取目标股票和板块
            target_stocks = self.config.get('target_stocks', [])
            target_sectors = self.config.get('target_sectors', [])
            
            # ===== 第一步：加载已有持仓（如果配置了的话）=====
            # 模拟盘可以从配置文件或之前的持仓状态加载
            initial_positions = self.config.get('initial_positions', {})
            holding_stocks = []
            
            if initial_positions:
                from position_management.position_manager import PositionInfo
                holding_stocks = list(initial_positions.keys())
                logger.info(f"📦 加载到 {len(holding_stocks)} 只初始持仓: {', '.join(holding_stocks)}")
                for stock, pos in initial_positions.items():
                    shares = pos.get('shares', 0)
                    cost = pos.get('cost_price', 0)
                    buy_date = pos.get('buy_date', datetime.now().strftime('%Y%m%d'))
                    
                    # 创建 PositionInfo 并添加到管理器
                    position_info = PositionInfo(
                        stock=stock,
                        buy_time=datetime.strptime(buy_date, '%Y%m%d') if buy_date else datetime.now(),
                        buy_price=cost,
                        shares=shares
                    )
                    position_info.initialize_stop_loss()
                    self.position_manager.add_position(stock, position_info)
                    
                    logger.info(f"   {stock}: {shares}股 @ {cost:.2f}元")
                    # 从初始资金中扣除持仓成本
                    self.capital -= shares * cost
            
            # ===== 第二步：合并监控范围 = 用户输入 + 持仓股票 =====
            # 将持仓股票自动加入监控范围
            if target_stocks:
                target_stocks = list(set(target_stocks) | set(holding_stocks))
            else:
                target_stocks = holding_stocks
            
            if holding_stocks:
                logger.info(f"✓ 监控范围已包含 {len(holding_stocks)} 只持仓股票")
            
            # 初始化策略数据
            if hasattr(self.strategy, 'initialize_data'):
                self.strategy.initialize_data(
                    mode="simulate", 
                    target_stocks=target_stocks, 
                    target_sectors=target_sectors
                )
            
            logger.info(f"开始模拟交易模式... 可用资金: {self.capital:,.2f}元")
            if target_stocks:
                logger.info(f"📊 最终监控范围: {len(target_stocks)} 只股票")
            if target_sectors:
                logger.info(f"📊 监控板块: {', '.join(target_sectors)}")
            
            while self.is_running:
                try:
                    if not self.strategy.check_market_status():
                        time.sleep(60)
                        continue
                    
                    # ===== 优先级1：止损检查（使用止损服务）=====
                    self._check_stop_loss()
                    
                    # ===== 优先级2：策略卖出信号 =====
                    self._check_sell_signals()
                    
                    # ===== 优先级3：买入信号 =====
                    self._check_buy_signals()
                    
                    # 输出当前状态
                    self._log_status()
                    
                    time.sleep(30)
                    
                except Exception as e:
                    logger.error(f"模拟交易执行异常: {str(e)}")
                    time.sleep(60)
                    
        except Exception as e:
            logger.error(f"模拟交易模式启动失败: {str(e)}")
    
    def _check_stop_loss(self):
        """检查止损（使用止损服务）"""
        if not self.stop_loss_service.is_enabled():
            return
        
        try:
            # 直接从 position_manager 获取所有持仓
            all_positions = self.position_manager.get_all_positions()
            if not all_positions:
                return
            
            # 准备止损服务需要的数据
            current_prices = {}
            current_date = datetime.now().strftime('%Y%m%d')
            
            for stock in all_positions.keys():
                # 获取当前价格
                current_prices[stock] = self.strategy.today_data.get(stock, {}).get('last', 0)
            
            # 调用止损服务检查（直接传入 position_manager 的持仓）
            stop_loss_list = self.stop_loss_service.check_all_positions(
                positions=all_positions,
                current_prices=current_prices,
                current_date=current_date
            )
            
            # 执行止损
            for stock, reason in stop_loss_list:
                logger.warning(f"🛑 触发止损: {stock} - {reason}")
                # 执行模拟卖出（全部清仓）
                self._execute_sell(stock, reason, sell_ratio=1.0)
        
        except Exception as e:
            logger.error(f"止损检查异常: {str(e)}", exc_info=True)
    
    def _check_sell_signals(self):
        """检查卖出信号（支持分批减仓）"""
        for stock in list(self.position_manager.get_all_positions().keys()):
            try:
                sell_result = self.strategy.check_sell_conditions(stock)
                if sell_result.get('should_sell', False):
                    sell_ratio = sell_result.get('sell_ratio', 1.0)  # 默认全部清仓
                    self._execute_sell(stock, sell_result['reason'], sell_ratio)
            except Exception as e:
                logger.error(f"检查{stock}卖出信号失败: {str(e)}")
    
    def _check_buy_signals(self):
        """检查买入信号"""
        for stock in self.strategy.stock_pool:
            if self.position_manager.get_position(stock):
                continue  # 已持仓
                
            try:
                if self.strategy.check_conditions(stock):
                    self._execute_buy(stock, "策略买入信号")
            except Exception as e:
                logger.error(f"检查{stock}买入信号失败: {str(e)}")
    
    def _execute_buy(self, stock, reason):
        """执行买入"""
        # 获取当前价格
        current_price = self.strategy.today_data.get(stock, {}).get('last', 0)
        if current_price <= 0:
            return
        
        # 计算买入数量
        max_shares = int(self.capital * 0.1 / current_price / 100) * 100  # 最多投入10%资金
        if max_shares < 100:
            return
        
        # 执行买入
        cost = current_price * max_shares
        if cost <= self.capital:
            self.capital -= cost
            
            # 创建 PositionInfo 并添加到 position_manager
            from position_management.position_manager import PositionInfo
            position_info = PositionInfo(
                stock=stock,
                buy_time=datetime.now(),
                buy_price=current_price,
                shares=max_shares
            )
            position_info.initialize_stop_loss()
            self.position_manager.add_position(stock, position_info)
            
            self.trades.append({
                'date': time.strftime('%Y%m%d %H:%M:%S'),
                'stock': stock,
                'action': 'buy',
                'price': current_price,
                'shares': max_shares,
                'amount': cost,
                'reason': reason
            })
            
            # 构建详细的买入原因（如果reason是简单字符串，则扩展它）
            buy_reason = reason
            if reason == "策略买入信号" or "买入条件" not in reason:
                try:
                    stock_today_data = self.strategy.today_data.get(stock, {})
                    volume_ratio = stock_today_data.get('volRatio', 0)
                    price_change_pct = stock_today_data.get('changePct', 0) * 100
                    strategy_type = self.strategy.last_strategy_type or "未知策略"
                    
                    # 构建详细买入原因
                    buy_reason_parts = [f"({strategy_type}) 买入条件："]
                    buy_reason_parts.append(f"突破5日线")
                    buy_reason_parts.append(f"量比{volume_ratio:.2f}")
                    if price_change_pct > 0:
                        buy_reason_parts.append(f"涨幅+{price_change_pct:.2f}%")
                    else:
                        buy_reason_parts.append(f"涨幅{price_change_pct:.2f}%")
                    buy_reason_parts.append("多头趋势")
                    buy_reason_parts.append("量价配合")
                    buy_reason = " + ".join(buy_reason_parts)
                except:
                    pass
            
            # 使用统一的交易输出格式化工具
            trade_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            
            # 获取股票名称
            stock_name = stock
            try:
                from xtquant import xtdata
                detail = xtdata.get_instrument_detail(stock)
                if isinstance(detail, dict):
                    stock_name_display = detail.get('InstrumentName', '')
                    if stock_name_display:
                        stock_name = f"{stock} ({stock_name_display})"
            except:
                pass
            
            commission = cost * 0.0001  # 默认手续费率
            total_cost = cost + commission
            actual_ratio = total_cost / self.capital * 100 if self.capital > 0 else 0
            
            # 输出买入信号（使用统一格式）
            output_lines = TradeFormatter.format_buy_output(
                stock_name=stock_name,
                trade_time=trade_time,
                price=current_price,
                actual_price=current_price,  # 模拟盘无滑点
                slippage_rate=0.0,
                shares=max_shares,
                amount=cost,
                commission=commission,
                total_cost=total_cost,
                remaining_capital=self.capital,
                reason=buy_reason,
                planned_ratio=None,
                actual_ratio=actual_ratio
            )
            
            # 输出到控制台
            print()  # 换行
            for line in output_lines:
                logger.info(line)
            
            # ===== 买入后更新监控范围 =====
            if hasattr(self.strategy, 'update_monitor_list'):
                # 转换 position_manager 数据为旧格式（兼容性）
                positions_dict = {
                    s: {'shares': p.shares, 'buy_price': p.buy_price, 'buy_date': p.buy_time.strftime('%Y%m%d')}
                    for s, p in self.position_manager.get_all_positions().items()
                }
                self.strategy.update_monitor_list(positions_dict)
    
    def _execute_sell(self, stock, reason, sell_ratio=1.0):
        """执行卖出（支持分批减仓）"""
        # 从 position_manager 获取持仓信息
        position_info = self.position_manager.get_position(stock)
        if not position_info:
            return
        
        current_price = self.strategy.today_data.get(stock, {}).get('last', 0)
        if current_price <= 0:
            return
        
        # 计算卖出数量
        total_shares = position_info.shares
        sell_shares = int(total_shares * sell_ratio)
        # 确保卖出股数是100的整数倍
        sell_shares = (sell_shares // 100) * 100
        
        if sell_shares <= 0:
            logger.warning(f"{stock} 计算卖出数量为0，跳过")
            return
        
        # 确保不超过持仓
        sell_shares = min(sell_shares, total_shares)
        is_full_sell = (sell_shares >= total_shares)
        
        # 执行卖出
        income = current_price * sell_shares
        self.capital += income
        
        profit = income - position_info.buy_price * sell_shares
        profit_rate = profit / (position_info.buy_price * sell_shares) * 100
        
        action_desc = "全部清仓" if is_full_sell else f"减仓{sell_ratio*100:.0f}%"
        
        self.trades.append({
            'date': time.strftime('%Y%m%d %H:%M:%S'),
            'stock': stock,
            'action': 'sell',
            'price': current_price,
            'shares': sell_shares,
            'amount': income,
            'profit': profit,
            'profit_rate': profit_rate,
            'reason': f"{reason} ({action_desc})"
        })
        
        # 使用统一的交易输出格式化工具
        trade_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        
        # 获取股票名称
        stock_name = stock
        try:
            detail = xtdata.get_instrument_detail(stock)
            if isinstance(detail, dict):
                stock_name_display = detail.get('InstrumentName', '')
                if stock_name_display:
                    stock_name = f"{stock} ({stock_name_display})"
        except:
            pass
        
        # 计算持有天数
        hold_days = 0
        if position_info.buy_time:
            try:
                buy_time = position_info.buy_time
                sell_time = datetime.now()
                hold_days = (sell_time - buy_time).days
            except:
                hold_days = 0
        
        commission = income * 0.0001  # 默认手续费率
        actual_sell_ratio = (sell_shares / total_shares * 100) if total_shares > 0 else 0
        
        # 输出卖出信号（使用统一格式）
        output_lines = TradeFormatter.format_sell_output(
            stock_name=stock_name,
            trade_time=trade_time,
            price=current_price,
            actual_price=current_price,  # 模拟盘无滑点
            slippage_rate=0.0,
            shares=sell_shares,
            sell_amount=income,
            commission=commission,
            remaining_capital=self.capital,
            reason=f"{reason} ({action_desc})",
            is_full_sell=is_full_sell,
            planned_sell_ratio=sell_ratio * 100,
            actual_sell_ratio=actual_sell_ratio,
            remaining_shares=total_shares - sell_shares,
            buy_price=position_info.buy_price,
            profit=profit,
            profit_rate=profit_rate,
            hold_days=hold_days,
            trigger_count=None
        )
        
        # 输出到控制台
        print()  # 换行
        for line in output_lines:
            logger.info(line)
        
        # 更新或删除 position_manager 中的持仓
        if is_full_sell:
            self.position_manager.remove_position(stock)
        else:
            # TODO: 未来可以添加 position_manager.reduce_shares() 方法
            position_info.shares = total_shares - sell_shares
            logger.info(f"  剩余持仓: {position_info.shares}股")
        
        # ===== 卖出后更新监控范围 =====
        if hasattr(self.strategy, 'update_monitor_list'):
            # 转换 position_manager 数据为旧格式（兼容性）
            positions_dict = {
                s: {'shares': p.shares, 'buy_price': p.buy_price, 'buy_date': p.buy_time.strftime('%Y%m%d')}
                for s, p in self.position_manager.get_all_positions().items()
            }
            self.strategy.update_monitor_list(positions_dict)
    
    def _log_status(self):
        """输出当前状态"""
        total_value = self.capital
        # 使用 position_manager 获取持仓
        for stock, position_info in self.position_manager.get_all_positions().items():
            current_price = self.strategy.today_data.get(stock, {}).get('last', 0)
            if current_price > 0:
                total_value += current_price * position_info.shares
        
        logger.info(f"💰 模拟交易状态 - 资金: {self.capital:,.2f}元, "
                   f"持仓: {len(self.position_manager.get_all_positions())}只, 总资产: {total_value:,.2f}元")

class MinuteBacktestExecutor(StrategyExecutor):
    """分钟级回测执行器"""
    
    def __init__(self, strategy_class, minute_backtest_system, **kwargs):
        super().__init__(strategy_class, ExecutionMode.MINUTE_BACKTEST, **kwargs)
        self.minute_backtest_system = minute_backtest_system
        
    def execute(self):
        """分钟级回测执行逻辑"""
        try:
            logger.info("开始分钟级回测模式...")
            
            # 使用分钟级回测系统
            default_end_date = datetime.now().strftime('%Y%m%d')
            
            results = self.minute_backtest_system.run_backtest(
                strategy_file=self.config.get('strategy_file', '突破5日线'),
                stock_list=self.config.get('stock_list', ['000001.SZ']),
                date=self.config.get('start_date', '20250101'),
                end_date=self.config.get('end_date', default_end_date)
            )
            
            # 检查回测是否成功完成
            if results and (results.get('success') or 'final_capital' in results):
                logger.info("分钟级回测完成")
                # 输出回测结果
                self.minute_backtest_system.print_summary()
                
                # 生成专业图表
                result_prefix = self.config.get('result_prefix', 'minute_backtest_result')
                
                # 生成图表（统一接口：交易分析 + K线图）
                try:
                    from professional_charts import generate_professional_charts
                    
                    # 获取日线数据用于K线图
                    daily_data = getattr(self.minute_backtest_system, 'daily_data', None)
                    
                    # 获取预测开始日期（K线图只显示预测期，不显示预热期）
                    warmup_start_date = results.get('warmup_start_date', None)
                    
                    # 尝试导入xtdata
                    xtdata_module = None
                    try:
                        from xtquant import xtdata as xtdata_module
                    except ImportError:
                        pass
                    
                    # 获取每日资金占用记录
                    daily_capital_usage = getattr(self.minute_backtest_system, 'daily_capital_usage', [])
                    
                    # 统一生成所有图表
                    generate_professional_charts(
                        trades=results['trades'],
                        initial_capital=self.minute_backtest_system.initial_capital,
                        daily_data=daily_data,
                        xtdata_module=xtdata_module,
                        save_path=f"{result_prefix}",
                        warmup_start_date=warmup_start_date,
                        daily_capital_usage=daily_capital_usage
                    )
                    
                    print(f"✅ 图表已生成:")
                    print(f"  📋 交易分析: {result_prefix}_交易分析.png")
                    print(f"  📊 K线图: {result_prefix}_[股票名称]_[股票代码]_kline.png")
                    
                except ImportError as e:
                    print(f"⚠️ 专业图表模块未找到: {str(e)}")
                    print("请确保 professional_charts.py 文件存在")
                    
                except Exception as e:
                    print(f"❌ 图表生成失败: {str(e)}")
                    import traceback
                    traceback.print_exc()
            else:
                logger.error(f"分钟级回测失败: {results.get('reason', '未知错误')}")
                
        except Exception as e:
            logger.error(f"分钟级回测模式执行失败: {str(e)}")
    

class StrategyManager:
    """策略管理器 - 统一管理多个策略和执行模式"""
    
    def __init__(self):
        self.executors = {}
        self.available_strategies = {}
        self._load_available_strategies()
    
    def _load_available_strategies(self):
        """加载可用策略"""
        import os
        import importlib.util
        
        strategies_dir = os.path.join(os.path.dirname(__file__), 'strategies')
        if not os.path.exists(strategies_dir):
            logger.warning("策略目录不存在")
            return
        
        try:
            # 使用UTF-8编码列出文件
            files = os.listdir(strategies_dir)
            logger.info(f"策略目录文件: {files}")
        except Exception as e:
            logger.error(f"无法读取策略目录: {str(e)}")
            return
        
        for filename in files:
            if filename.endswith('.py') and not filename.startswith('__'):
                strategy_name = filename[:-3]
                try:
                    logger.info(f"正在加载策略: {strategy_name}")
                    
                    # 动态导入策略
                    file_path = os.path.join(strategies_dir, filename)
                    spec = importlib.util.spec_from_file_location(strategy_name, file_path)
                    module = importlib.util.module_from_spec(spec)
                    spec.loader.exec_module(module)
                    
                    # 查找策略类
                    strategy_class = None
                    for name in dir(module):
                        obj = getattr(module, name)
                        if (isinstance(obj, type) and 
                            name.endswith('Strategy') and 
                            hasattr(obj, 'check_conditions')):
                            strategy_class = obj
                            break
                    
                    if strategy_class:
                        self.available_strategies[strategy_name] = strategy_class
                        logger.info(f"成功加载策略: {strategy_name}")
                    else:
                        logger.warning(f"策略文件 {strategy_name} 中未找到有效的策略类")
                            
                except Exception as e:
                    logger.error(f"加载策略 {strategy_name} 失败: {str(e)}")
                    import traceback
                    logger.error(f"详细错误: {traceback.format_exc()}")
        
        logger.info(f"总共加载了 {len(self.available_strategies)} 个策略")
    
    def get_available_strategies(self):
        """获取可用策略列表"""
        return list(self.available_strategies.keys())
    
    def create_executor(self, strategy_name: str, mode: ExecutionMode, **kwargs):
        """创建策略执行器"""
        if strategy_name not in self.available_strategies:
            raise ValueError(f"策略 {strategy_name} 不存在")
        
        strategy_class = self.available_strategies[strategy_name]
        
        if mode == ExecutionMode.MONITOR:
            executor = MonitorExecutor(strategy_class, **kwargs)
        elif mode == ExecutionMode.LIVE_TRADE:
            executor = LiveTradeExecutor(strategy_class, **kwargs)
        elif mode == ExecutionMode.SIMULATE:
            executor = SimulateExecutor(strategy_class, **kwargs)
        elif mode == ExecutionMode.MINUTE_BACKTEST:
            # 导入分钟级回测系统
            from backtest_systems.分时回测 import MinuteStrategyBacktest
            minute_backtest_system = MinuteStrategyBacktest()
            executor = MinuteBacktestExecutor(strategy_class, minute_backtest_system, **kwargs)
        else:
            raise ValueError(f"不支持的执行模式: {mode}")
        
        executor_id = f"{strategy_name}_{mode.value}_{int(time.time())}"
        self.executors[executor_id] = executor
        return executor_id, executor
    
    def start_executor(self, executor_id: str):
        """启动执行器"""
        if executor_id in self.executors:
            self.executors[executor_id].start()
        else:
            raise ValueError(f"执行器 {executor_id} 不存在")
    
    def stop_executor(self, executor_id: str):
        """停止执行器"""
        if executor_id in self.executors:
            self.executors[executor_id].stop()
        else:
            raise ValueError(f"执行器 {executor_id} 不存在")
    
    def stop_all_executors(self):
        """停止所有执行器"""
        for executor in self.executors.values():
            executor.stop()
        self.executors.clear()
    
    def get_executor_status(self):
        """获取执行器状态"""
        status = {}
        for executor_id, executor in self.executors.items():
            status[executor_id] = {
                'mode': executor.mode.value,
                'strategy': executor.strategy_class.__name__,
                'running': executor.is_running
            }
        return status
